<?php
/**
 * @author Akulov Denis
 * @since 03.07.2011
 */
class MVC_Carcass {

    const MAIN_REQUEST_ID           = '::main_request::';
    const FILE_KEY                  = 'CARCASS_FILE';
    const MVC_NODES_KEY             = 'MVC_NODES';
    const CARCASS_MVCPATH_DELIMITER = '/';

    private $_strCarcassFolder = '';


    private $_strCarcassFile = '';


    private $_strMainRequest = '';


    private $_arCarcassRules = array();


    private $_strCarcass = '';


    private $_arSettings = '';


    private $_arMvcNodes = array ();


    public function __construct ($strCarcassFolder, $strMainRequest, $arCarcassRules) {
        $this->setCarcassFolder($strCarcassFolder);
        $this->setMainRequest($strMainRequest);
        $this->setCarcassRules($arCarcassRules);
        $this->initialization();
    }


    /**
     * @return array[]
     */
    public function getMvcNodes () {
        if (empty($this->_arMvcNodes)) {
            $arMvcNodes = $this->getSettingAttribute(self::MVC_NODES_KEY);
            $arResult = array();
            foreach ($arMvcNodes as $item) {
                $key = '<!--@'.implode(self::CARCASS_MVCPATH_DELIMITER, $item).' -->';
                if ($item[0] == self::MAIN_REQUEST_ID) {
                    $arResult[$key] = $item;
                    continue;
                }
                $arResult[$key][] = $item[0];
                $arResult[$key][] = $item[1];
                unset($item[0]);
                unset($item[1]);
                $arResult[$key][] = array_values($item);
            }
            $this->setMvcNodes($arResult);
        }

        return $this->_arMvcNodes;
    }


    public function parse ($arMvcNodesResult) {
        $strResult = $this->getCarcass();
        foreach ($arMvcNodesResult as $pattern => $strMvcNodeResult) {
            $strResult = str_replace($pattern, $strMvcNodeResult, $strResult);
        }
        return $strResult;
    }


    private function setMvcNodes ($arMvcNodes) {
        $this->_arMvcNodes = $arMvcNodes;
    }


    private function initialization () {
        foreach ($this->getCarcassRules() as $pattern => $settings) {
            if (preg_match($pattern, $this->getMainRequest())) {
                $this->setSettings($settings);
                break;
            }
        }
    }


    protected function readCarcass () {
        if (is_file($this->getCarcassFile())) {
            return file_get_contents($this->getCarcassFile());
        }
        throw new Exception('Carcass file not found');
    }


    /**
     * @param string $attribute
     * @return string
     */
    public function getSettingAttribute ($attribute) {
        return $this->_arSettings[$attribute];
    }


    /**
     * @return string
     */
    public function getCarcassFolder () {
        return $this->_strCarcassFolder;
    }

    private function setCarcassFolder ($strFolder) {
        $this->_strCarcassFolder = $strFolder;
    }


    /**
     * @return string
     */
    public function getMainRequest () {
        return $this->_strMainRequest;
    }


    private function setMainRequest ($strRequest) {
        if (substr($strRequest, 0, 1) == '/') {
            $strRequest = substr($strRequest, 1);
        }
        $this->_strMainRequest = $strRequest;
    }


    /**
     * @return array[]
     */
    public function getCarcassRules () {
        return $this->_arCarcassRules;
    }


    private function setCarcassRules ($arRules) {
        $this->_arCarcassRules = $arRules;
    }


    /**
     * @return string
     */
    public function getCarcass () {
        if (empty($this->_strCarcass)) {
            $this->setCarcass($this->readCarcass());
        }
        return $this->_strCarcass;
    }


    private function setCarcass ($strCarcass) {
        $this->_strCarcass = $strCarcass;
    }


    /**
     * @return array[]
     */
    public function getSettings () {
        return $this->_arSettings;
    }


    private function setSettings ($arSettings) {
        $this->_arSettings = $arSettings;
    }


    /**
     * @return string
     */
    public function getCarcassFile () {
        if (empty($this->_strCarcassFile)) {
            $this->setCarcassFile(
                $this->getCarcassFolder().
                $this->getSettingAttribute(self::FILE_KEY)
            );
        }
        return $this->_strCarcassFile;
    }


    private function setCarcassFile ($strFileCarcass) {
        $this->_strCarcassFile = $strFileCarcass;
    }
}